/**
 * Copyright (C) 2008 aileron.cc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package cc.aileron.commons.logging;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Properties;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * logging interceptor
 * @author Aileron
 *
 */
public class LoggingInterceptor implements MethodInterceptor 
{
	/**
	 * logging-level
	 */
	private final LoggingLevel level;
	
	/**
	 * loggging-interface
	 */
	private final LoggingInterface loggingInterface;
	
	/**
	 * setting-map
	 */
	private final Properties settingMap;
	
	/**
	 * logging-level の　設定
	 * @param level
	 */
	public LoggingInterceptor(
	        final LoggingLevel level,
	        final Properties properties,
	        final LoggingInterface loggingInterface)
	{
		this.level = level;
		this.loggingInterface = loggingInterface;
		this.settingMap = properties;
	}
	
	/**
	 * log-level を取得する
	 * @param key
	 * @return
	 */
	private LoggingLevel getLogLevel(final String key)
	{
	    final String tmp = settingMap.getProperty( key );
	    return tmp==null ? LoggingLevel.NONE : LoggingLevel.valueOf(tmp);
	}
	
	public Object invoke(final MethodInvocation methodInvocation) throws Throwable 
	{
	    final String methodName = methodInvocation.getMethod().getName();
		final String className;
		{
			className = methodInvocation.getThis().getClass().getName().split("\\$\\$")[0].replace('$', '.');
		}
		final LoggingLevel level = getLogLevel(className+"."+methodName);
		final boolean isLogging = this.level.compare(level);
		if(isLogging)
		{
		    loggingInterface.startLog(level, className, methodName, "");
			loggingInterface.invokeLog( Arrays.asList(methodInvocation.getArguments()) );
		}
		final Object result;
		try
		{
		    result = methodInvocation.proceed();
		}
		catch(Throwable e)
		{
		    if(isLogging)
		    {
		        final StringWriter sw = new StringWriter();
		        final PrintWriter pw = new PrintWriter(sw,true);
		        e.printStackTrace(pw);
		        pw.close();
		        loggingInterface.resultLog(sw.toString());
		    }
		    throw e;
		}
		if(isLogging)
		{
		    loggingInterface.resultLog(result);
		}
		return result;
	}
}
